"""--------------------------------------------------------------------------------------------------
Filename:   targetFacory.py
Author:     Ben Han (uha10@uclive.ac.nz)
Date:       17 May 2010
Description:
    Main plotting module for biofeedback application
--------------------------------------------------------------------------------------------------"""
from __future__ import division
import random
import sys



"""--------------------------------------------------------------------------------------------------
  CLASS: TargetFactory
    This class creates and returns the targets for the skill training.
--------------------------------------------------------------------------------------------------"""
class TargetFactory:
    """ Holds information about the target polygon
        position[x,y] gives the coordinates of the target (bottom left, top right corners respectively)
        size[x,y] holds the dimensions of the target
    """

    def __init__(self, cfg, state):
        '''
        ==============  =====================================
        **Arguments:**
        state           (State) reference to the current state
                         of the session
        cfg             (Config) configuration object
        ==============  =====================================
       '''

        self.cfg = cfg
        self.sess_status = state
        self.x_lim = cfg.trial_len
        
        self.position = [0, 0]      # target coordinates (bottom left corner)
        self.size = [0, 0]          # target dimensions
        self.range_min = [0, 0]     # coordinates of the bottom left corner of the range [x,y]
        self.range_max = [0, 0]     # coordinates of the top right corner of the range [x,y]
        self.size_min = [0, 0]      # minimum values for the target size [x,y]
        self.size_max = [0, 0]      # maximum values for the target size [x,y]
        
    def set_range_min(self, minimum):
        '''
        Set the minimum range of the target
        ==============  =====================================
        **Arguments:**
        minimum         (float) Minimum range 
        ==============  =====================================
       '''
        self.range_min = minimum
        
    def set_range_max(self, maximum):
        '''
        Set the maximum range of the target
        ==============  =====================================
        **Arguments:**
        maximum         (float) Minimum range 
        ==============  =====================================
       '''
        self.range_max = maximum
        
    def set_size_limits(self):
        '''
        Set the size limits of the targets in the session status

        '''
        self.size_min[0] = self.sess_status.min_size[0]
        self.size_max[0] = self.sess_status.max_size[0]
        self.size_min[1] = self.sess_status.min_size[1]
        self.size_max[1] = self.sess_status.max_size[1]

    def get_limits(self):
        '''
        Return the range and size limits of the target

        '''
        
        limits = [self.range_min[0], self.range_max[0], self.range_min[1], self.range_max[1], \
                  self.size_min[0], self.size_max[0], self.size_min[1], self.size_max[1], \
                  self.axes, self.cfg, self.x_lim]
        return limits

    def recalc(self, change, init=False):
        """ Recalculate the target position and size
        
        inputs:    change      (int) Change in consecutive hits
                                Expected to be -1,0,1
        
        returns:   position    [x,y]
                   size        [xLen,yLen]
    
        """
        adj = 1 - (float(self.cfg.incrementPer) / 100)
        if self.sess_status.trial_index == 1:
            init = True
        # adjust target size based on history of hits/misses
        if init:
            
            # Set initial target size
            self.size[0] = self.cfg.init_size_x
            self.size[1] = self.sess_status.baseline * self.cfg.init_size_y / 100
            
            self.range_max[1] = self.sess_status.baseline* self.cfg.init_max_range / 100
            self.range_min[1] = self.sess_status.baseline* self.cfg.init_min_range / 100

        elif change > 0:
            self.size[1] = self.size[1] / adj    # increase size
            self.size[0] = self.size[0] / adj

        elif change < 0:
            self.size[1] = self.size[1] * adj    # decrease size
            self.size[0] = self.size[0] * adj



        """ Set random position on the screen within given range, and ensure that the target
            is completely inside the range limits.
        """
        print "size"
        print self.size
        
        sizeTemp = [0,0]
        sizeTemp[0] = self.size[0]
        sizeTemp[1] = self.size[1]

        # Firstly, test to see if the target is able to fit completely inside the range limits,
        # otherwise set the size to the limit.
        if sizeTemp[1] > (self.range_max[1] - self.range_min[1]):     # amplitude size
            sizeTemp[1] = self.range_max[1] - self.range_min[1]
            print "max reached"
            
            # make sure size actually decreases (removes any size increase if the maximum is reached)
            if change < 0:

                while self.size[1] > (self.range_max[1] - self.range_min[1]): 
                    self.size[1] = self.size[1] * adj    # increase size
                    self.size[0] = self.size[0] * adj
                
                sizeTemp[0] = self.size[0]
                sizeTemp[1] = self.size[1]   

            
        if self.cfg.target_aspect_ratio:
            # Make target look square on screen
            trial_len = long(self.cfg.trial_len)
            yMax = long(self.cfg.y_axis_max)
            
            # avoid any divide by 0 errors
            if yMax == 0:
                yMax = self.cfg.y_axis_max_init
                    
                    
            pixel_ratio = self.cfg.plot_x_pixel/self.cfg.plot_y_pixel
            
            # creates a square ratio based on the axis values and the axis pixel ratio
            ratio = float(trial_len/yMax) * pixel_ratio

            sizeTemp[0] = float(sizeTemp[1] * ratio)
                        
        if sizeTemp[0] > (self.range_max[0] - self.range_min[0]):     # temporal size
            sizeTemp[0] = self.range_max[0] - self.range_min[0]

        # Set (r1, r2) to (lower left, upper right) limits for random placement
        r1 = [ self.range_min[0], self.range_min[1] ]
        r2 = [ self.range_max[0] - sizeTemp[0], self.range_max[1] - sizeTemp[1] ]

        
        # Set the bottom left corner of the target to a random point inside the range
        self.position[0] = (r2[0] - r1[0]) * random.random() + r1[0]
        self.position[1] = (r2[1] - r1[1]) * random.random() + r1[1]
        
        self.x1 = self.position[0]
        self.y1 = self.position[1]
        self.x2 = self.position[0] + sizeTemp[0]
        self.y2 = self.position[1] + sizeTemp[1]
        print "=== Target parameters ================================"
        print "    pos     (x,y): (%.2f, %.2f)" % (self.position[0], self.position[1])
        print "    size    (x,y): (%.2f, %.2f)" % (sizeTemp[0], sizeTemp[1])
        print "======================================================"

        return [self.position,sizeTemp]


# End of targetfactory.py